fix(server): stop the reaper from silently killing live background subagents - #5677
Conversation
The inactivity reaper only checked activeTurnId, but background subagent fleets, workflow runs, and monitors keep working after the turn settles and nothing bumps lastSeenAt between turns. After 30 idle minutes the reaper stopped the session and silently killed all of them. The thread shell already carries backgroundLiveness from ThreadBackgroundLivenessService; the sweep now skips threads with live background work, same as it skips active turns. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: Scenario and decoded snapshot size10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
ApprovabilityVerdict: Approved 104ac59 This is a straightforward bug fix that adds a guard condition to prevent the session reaper from killing sessions with active background work. The change follows the existing pattern in the code, is well-tested, and has limited scope. You can customize Macroscope's approvability policy. Learn more. |
…bagents (pingdotgg#5677) Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…bagents (pingdotgg#5677) Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…bagents (pingdotgg#5677) Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…bagents (pingdotgg#5677) Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…bagents (pingdotgg#5677) Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
## What's Changed * fix(server): stop the reaper from silently killing live background subagents by @t3dotgg in pingdotgg/t3code#5677 **Full Changelog**: pingdotgg/t3code@v0.0.33-nightly.20260808.1030...v0.0.33-nightly.20260808.1031 Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.33-nightly.20260808.1031
…bagents (pingdotgg#5677) Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…bar-default-a13c sync: port upstream sidebar v2 default, Stop button, and late polish (pingdotgg#5554–pingdotgg#5677)
The session reaper stops an agent whose thread has stayed quiet for longer than a threshold. That threshold was a constant in the source: thirty minutes, changeable only by editing the code and rebuilding the server. It is now a user setting, `providerSessionIdleTimeout`. The reaper reads it at the start of every sweep, not once when the server starts. Reading it on every sweep is the point. Applying a longer timeout by restarting the server would stop the very sessions the longer timeout exists to protect. Zero means never stop an idle agent. This commit no longer carries the guard that spares a thread with live background work. Upstream shipped its own version of that guard in "fix(server): stop the reaper from silently killing live background subagents" (pingdotgg#5677), and the fork now uses upstream's. What remains here is the configurable timeout, its entry in the settings panel and the settings search, its schema in the shared contracts package, and a policy test that pairs the timeout with each background-work state. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The session reaper stops an agent whose thread has stayed quiet for longer than a threshold. That threshold was a constant in the source: thirty minutes, changeable only by editing the code and rebuilding the server. It is now a user setting, `providerSessionIdleTimeout`. The reaper reads it at the start of every sweep, not once when the server starts. Reading it on every sweep is the point. Applying a longer timeout by restarting the server would stop the very sessions the longer timeout exists to protect. Zero means never stop an idle agent. This commit no longer carries the guard that spares a thread with live background work. Upstream shipped its own version of that guard in "fix(server): stop the reaper from silently killing live background subagents" (pingdotgg#5677), and the fork now uses upstream's. What remains here is the configurable timeout, its entry in the settings panel and the settings search, its schema in the shared contracts package, and a policy test that pairs the timeout with each background-work state. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Upstream's pingdotgg#5219 (native subagent & workflow observability) and pingdotgg#5677 (stop the reaper killing live background subagents) put two shared registries behind the projection snapshot query: ThreadBackgroundLivenessService and ThreadPlanProgressService. The fork's crash-recovery reconciler test builds its own layer rather than reusing orchestration/runtimeLayer.ts, so it did not pick them up and failed typecheck with an unfilled Layer context. Provided rather than provideMerge'd — nothing in this test reads the registries directly, so they need satisfying, not re-exporting. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
## What's Changed * fix(mobile): reconnects no longer shift the thread list by @t3dotgg in pingdotgg/t3code#5372 * feat(web): drag pinned threads into your own order by @t3dotgg in pingdotgg/t3code#5581 * chore(ci): vouch StiensWout by @t3-code[bot] in pingdotgg/t3code#5637 * feat(desktop): remember recently used sites in the Browser panel by @chrisdeeming in pingdotgg/t3code#5270 * chore: vouch chrisdeeming by @t3-code[bot] in pingdotgg/t3code#5641 * feat(web): make sidebar artwork theme-aware by @maria-rcks in pingdotgg/t3code#5636 * fix(web): reconnect the composer seam for remote non-Git projects by @caezium in pingdotgg/t3code#5633 * fix(web): show Stop button while input is pending by @ipanasenko in pingdotgg/t3code#5554 * feat(web): fold plan mode and token-by-token output into Legacy features by @t3dotgg in pingdotgg/t3code#5664 * feat: sidebar v2 is now the default sidebar by @t3dotgg in pingdotgg/t3code#5672 * fix(server): stop PR status lookups amplifying GitHub rate limits by @t3dotgg in pingdotgg/t3code#5673 * fix(web): delay transient reconnect warnings by @t3-code[bot] in pingdotgg/t3code#5670 * fix(web): inherit terminal size in simple typography by @chrisdeeming in pingdotgg/t3code#5628 * fix(server): stop the reaper from silently killing live background subagents by @t3dotgg in pingdotgg/t3code#5677 * fix(desktop): zoom shortcuts no longer die when the preview browser has focus by @t3dotgg in pingdotgg/t3code#5691 * feat(mobile): one sheet for model and thread settings by @t3dotgg in pingdotgg/t3code#5625 * feat(usage): usage page reading provider transcripts across environments by @t3dotgg in pingdotgg/t3code#5684 * fix(web): usage chart no longer makes Claude look like the bigger spender by @t3dotgg in pingdotgg/t3code#5697 * fix(web): persist diff view mode by @leorivastech in pingdotgg/t3code#5731 * feat(web): show how many subagents are running at a glance by @t3dotgg in pingdotgg/t3code#5745 * fix(web): add missing cursor-pointer styling to dropdowns and interactive buttons by @naMqe-h in pingdotgg/t3code#5716 * fix(server): stop Claude resume handshakes from completing turns that never ran by @gfsaaser24 in pingdotgg/t3code#5710 * chore: vouch gfsaaser24 by @t3dotgg in pingdotgg/t3code#5761 * chore: vouch saphid by @t3dotgg in pingdotgg/t3code#5763 * fix(server): stop Codex threads with queued follow-ups by @t3dotgg in pingdotgg/t3code#5762 * fix(web): usage page loses the cost quality panel, gains a back button by @t3dotgg in pingdotgg/t3code#5756 * feat(server): agents can now open the images you paste into chat by @t3dotgg in pingdotgg/t3code#5757 * fix(web): pinned reorder no longer reshuffles while writes land by @t3dotgg in pingdotgg/t3code#5767 * feat(web): overhaul project settings into a real settings page by @t3dotgg in pingdotgg/t3code#5768 * fix(web): usage totals no longer jump while devices report in by @t3dotgg in pingdotgg/t3code#5772 * fix(server): settle no longer leaves monitors and dev servers running by @t3dotgg in pingdotgg/t3code#5774 * feat: pick worktree or current checkout per project by @t3dotgg in pingdotgg/t3code#5766 * fix(web): sidebar rows show the branch again, not a truncated plan step by @t3dotgg in pingdotgg/t3code#5776 * feat(server): vp run migrate-dev-db seeds worktree dev dbs with real data by @t3dotgg in pingdotgg/t3code#5773 * feat(web): keep unsent drafts one click away in the sidebar by @t3dotgg in pingdotgg/t3code#5777 * feat(web): project icons can be chosen manually by @t3dotgg in pingdotgg/t3code#5775 * fix(server): one greedy agent process no longer takes down the whole server by @t3dotgg in pingdotgg/t3code#5788 * ci: label-gated hosted-web preview deploys by @t3dotgg in pingdotgg/t3code#5465 * Add cross-platform mobile usage dashboard by @juliusmarminge in pingdotgg/t3code#5743 * fix(web): preserve desktop route during Clerk auth by @wobsoriano in pingdotgg/t3code#5770 * fix(web): match create theme and import theme buttons to the standard outline style by @UtkarshUsername in pingdotgg/t3code#5860 * fix(server): favicon resolution no longer pins the event loop by @murenovich in pingdotgg/t3code#5538 * fix(shared): bound the file-link label so bracket runs stop rescanning by @tsouth89 in pingdotgg/t3code#5782 * fix(web): thread title button no longer eats the drag area by @nathangerday in pingdotgg/t3code#5857 * fix(web): unify usage page chrome by @t3-code[bot] in pingdotgg/t3code#5823 * fix(shell): add ~/.local/bin to the Windows CLI resolver so native-installed providers are found by @arhxam in pingdotgg/t3code#5074 * fix(web): match settings search shortcut styling to command palette's by @UtkarshUsername in pingdotgg/t3code#5841 * fix(mobile): long-pressing a thread row no longer navigates into the thread by @juliusmarminge in pingdotgg/t3code#5901 * fix(server): usage no longer double-counts forked Codex sessions by @t3dotgg in pingdotgg/t3code#5887 * fix(server): sandbox user-provided SVGs by @t3dotgg in pingdotgg/t3code#5916 * fix(web): match usage titlebar text styling by @t3-code[bot] in pingdotgg/t3code#5897 * Move project settings to contextual project routes by @juliusmarminge in pingdotgg/t3code#5923 * Retain thread sidebar data when navigating to /settings so back navigation is instant by @juliusmarminge in pingdotgg/t3code#5930 * Automate production mobile EAS releases by @juliusmarminge in pingdotgg/t3code#5609 * Add settings and usage breadcrumbs by @juliusmarminge in pingdotgg/t3code#5929 * fix(web): correct model picker trigger padding by @Chrono-byte in pingdotgg/t3code#5935 * fix(web): show worktree icon in sidebar v2 by @tris203 in pingdotgg/t3code#5909 * fix(web): enable restore defaults after theme mix changes by @Lucenx9 in pingdotgg/t3code#5928 * fix(web): trait menu closes after you pick a level by @t3dotgg in pingdotgg/t3code#5879 * fix(web): align project name with headline by @carterwsmith in pingdotgg/t3code#5864 * fix(web): update pills use readable theme foregrounds by @chrisdeeming in pingdotgg/t3code#5938 * fix(web): use themed confirmation dialogs by @StiensWout in pingdotgg/t3code#5624 * fix(web): use import/export-appropriate icons for theme buttons by @UtkarshUsername in pingdotgg/t3code#5964 * fix(mobile): detect PowerShell cmdlet errors in work log rows by @myacoub91 in pingdotgg/t3code#5726 * fix(mobile): stop Android user bubbles with code blocks from overlapping by @Brechard in pingdotgg/t3code#5659 * fix(mobile): parse EAS fingerprint JSON by @juliusmarminge in pingdotgg/t3code#5991 ## New Contributors * @chrisdeeming made their first contribution in pingdotgg/t3code#5270 * @wobsoriano made their first contribution in pingdotgg/t3code#5770 * @murenovich made their first contribution in pingdotgg/t3code#5538 * @tsouth89 made their first contribution in pingdotgg/t3code#5782 * @nathangerday made their first contribution in pingdotgg/t3code#5857 * @carterwsmith made their first contribution in pingdotgg/t3code#5864 * @myacoub91 made their first contribution in pingdotgg/t3code#5726 **Full Changelog**: pingdotgg/t3code@v0.0.32...v0.0.33 Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.33
Upstream's pingdotgg#5219 (native subagent & workflow observability) and pingdotgg#5677 (stop the reaper killing live background subagents) put two shared registries behind the projection snapshot query: ThreadBackgroundLivenessService and ThreadPlanProgressService. The fork's crash-recovery reconciler test builds its own layer rather than reusing orchestration/runtimeLayer.ts, so it did not pick them up and failed typecheck with an unfilled Layer context. Provided rather than provideMerge'd — nothing in this test reads the registries directly, so they need satisfying, not re-exporting. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Background subagent fleets, workflow runs, and monitor watch loops kept getting killed mid-work with no signal to the user. The session reaper was the culprit: it only skips threads with an active turn, but background work runs on after the turn settles, and nothing bumps the binding's
lastSeenAtbetween turns. Thirty idle minutes later the sweep calledstopSession, tearing down the provider process and everything running inside it.The thread shell the reaper already fetches carries
backgroundLivenessfromThreadBackgroundLivenessService(the same signal the sidebar pill uses: "working" for live agent work, "monitoring" for watch loops). The sweep now skips threads with live background work, exactly like it skips active turns, and logs the skip. The liveness registry is in-memory and empty after a server restart, so orphaned bindings still get reaped.Also folded the reaper tests' repeated start boilerplate into a helper so the new test stays under the file's manual-runner lint baseline.
Change authored by Claude Fable 5 via Claude Code.
Note
Medium Risk
Changes when long-idle provider sessions are stopped; wrong liveness could leave sessions running longer or still reap too aggressively after restart when the in-memory registry is empty.
Overview
The provider session reaper no longer calls
stopSessionon idle bindings when the thread shell reportsbackgroundLiveness(workingormonitoring), mirroring the existing skip for an active turn. That closes a gap where subagent fleets, workflows, and monitor loops could keep running after the turn settled without refreshinglastSeenAt, so inactivity sweeps tore down the provider process with no user-visible signal. Skips are logged asprovider.session.reaper.skipped-background-work.Tests now model
backgroundLivenesson the read-model fixture, add coverage for the skip path, and centralize reaper startup in astartReaperhelper (including drain/assertions on the active-turn case).Reviewed by Cursor Bugbot for commit 104ac59. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Fix
ProviderSessionReaperto skip sessions with live background subagentsThe reaper previously stopped sessions without checking whether background subagents were still active. A new guard in
ProviderSessionReaper.tschecks the thread'sbackgroundLivenessfield from the projection snapshot and skipsstopSessionif it is non-null, logging aprovider.session.reaper.skipped-background-workdebug event instead. A corresponding test inProviderSessionReaper.test.tscovers the new skip behavior withbackgroundLivenessset to"working".Macroscope summarized 104ac59.